export const getType = (value: unknown) => {
    if (null === value) {
        return 'null';
    }
    const type = typeof value;
    if ('undefined' === type || 'string' === type) {
        return type;
    }
    const typeString = Object.prototype.toString.call(value);
    const TYPE_CONFIG: Record<string, string> = {
        '[object Array]': 'array',
        '[object Date]': 'date',
        '[object Boolean]': 'boolean',
        '[object Number]': 'number',
        '[object Function]': 'function',
        '[object RegExp]': 'regexp',
        '[object Object]': 'object',
        '[object Symbol]': 'symbol',
        '[object Map]': 'map',
        '[object Set]': 'set'
    };
    return TYPE_CONFIG[typeString] || 'unknow';
};

export const isMap = (val: unknown): val is Map<unknown, unknown> => getType(val) === 'map';
export const isSet = (val: unknown): val is Set<unknown> => getType(val) === 'set';

export const isRegexp = (val: unknown): val is RegExp => getType(val) === 'regexp';
export const { isArray } = Array;
export const isDate = (val: unknown): val is Date => val instanceof Date;
export function isUndefined(val: unknown): val is undefined {
    return val === undefined;
}
export const isSymbol = (value: unknown) => {
    const type = typeof value;
    return (
        type === 'symbol' || (type === 'object' && value !== null && getType(value) === 'symbol')
    );
};

export const isObject = (val: unknown): val is { [key: string]: unknown } => {
    return getType(val) === 'object';
};

export function isEmptyObject(obj: unknown): boolean {
    return isObject(obj) && Object.keys(obj).length === 0;
}
export const isBoolean = (val: unknown): val is boolean => getType(val) === 'boolean';
// 原始数据类型 Types: number , string , boolean , symbol, bigint, undefined, null
export const isPrimitive = (value: unknown): boolean => {
    return (
        value === undefined ||
        value === null ||
        (typeof value !== 'object' && typeof value !== 'function')
    );
};
export const isObjectLike = (value: unknown) => {
    return typeof value === 'object' && value !== null;
};

export const isNumber = (value: unknown) => {
    return typeof value === 'number' || (isObjectLike(value) && getType(value) === 'number');
};

export const { isNaN } = Number;

export const isPromise = (value: any): value is Promise<any> => {
    if (!value) return false;
    if (!value.then) return false;
    if (!isFunction(value.then)) return false;
    return true;
};

export const isFloat = (value: any): value is number => {
    return isNumber(value) && value % 1 !== 0;
};
export const isInt = (value: any): value is number => {
    return isNumber(value) && value % 1 === 0;
};

export const isFunction = function (value: any): value is Function {
    return typeof value === 'function' ? true : false;
};

export const isString = (value: any): value is string => {
    return typeof value === 'string' || value instanceof String;
};

export const isEmpty = (value: any) => {
    if (value === true || value === false) return true;
    if (value === null || value === undefined) return true;
    if (isNumber(value)) return value === 0;
    if (isDate(value)) return isNaN(value.getTime());
    if (isFunction(value)) return false;
    if (isSymbol(value)) return false;
    const { length } = value as any;
    if (isNumber(length)) return length === 0;
    const { size } = value as any;
    if (isNumber(size)) return size === 0;
    const keys = Object.keys(value).length;
    return keys === 0;
};

export const isEqual = <TType>(x: TType, y: TType): boolean => {
    if (Object.is(x, y)) return true;
    if (x instanceof Date && y instanceof Date) {
        return x.getTime() === y.getTime();
    }
    if (x instanceof RegExp && y instanceof RegExp) {
        return x.toString() === y.toString();
    }
    if (typeof x !== 'object' || x === null || typeof y !== 'object' || y === null) {
        return false;
    }
    const keysX = Reflect.ownKeys(x as unknown as object) as (keyof typeof x)[];
    const keysY = Reflect.ownKeys(y as unknown as object);
    if (keysX.length !== keysY.length) return false;
    for (let i = 0; i < keysX.length; i++) {
        if (!Reflect.has(y as unknown as object, keysX[i])) return false;
        if (!isEqual(x[keysX[i]], y[keysX[i]])) return false;
    }
    return true;
};
